package hmvictor.jpql;

import hmvictor.jpql.nodes.ConnectionChildFactory;
import hmvictor.jpql.nodes.ConnectionNode;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.stream.Collectors;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.view.ListView;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;

/**
 * Top component which displays something.
 */
@ConvertAsProperties(
        dtd = "-//hmvictor.jpql//Connections//EN",
        autostore = false
)
@TopComponent.Description(
        preferredID = "ConnectionsTopComponent",
        //iconBase="SET/PATH/TO/ICON/HERE", 
        persistenceType = TopComponent.PERSISTENCE_ALWAYS
)
@TopComponent.Registration(mode = "explorer", openAtStartup = true)
@ActionID(category = "Window", id = "hmvictor.jpql.ConnectionsTopComponent")
@ActionReference(path = "Menu/Window" /*, position = 333 */)
@TopComponent.OpenActionRegistration(
        displayName = "#CTL_ConnectionsAction",
        preferredID = "ConnectionsTopComponent"
)
@Messages({
    "CTL_ConnectionsAction=Connections",
    "CTL_ConnectionsTopComponent=Connections",
    "HINT_ConnectionsTopComponent=This is a Connections window"
})
public final class ConnectionsTopComponent extends TopComponent implements ExplorerManager.Provider {

    private final List<Connection> connections = new LinkedList<>();

    public ConnectionsTopComponent() {
        initComponents();
        setName(Bundle.CTL_ConnectionsTopComponent());
        setToolTipText(Bundle.HINT_ConnectionsTopComponent());
        listViewPanel.add(new ListView());
    }

    public List<Connection> getConnections() {
        return connections;
    }

    private void saveConnections() throws IOException, XMLStreamException {
        File file = new File(AppFiles.getAndCreateConfigDir(), "connections.xml");
        XMLOutputFactory output = XMLOutputFactory.newInstance();
        XMLStreamWriter writer = output.createXMLStreamWriter(new FileWriter(file));
        writer.writeStartDocument();
        writer.writeStartElement("connections");
        for (Connection connection : connections) {
            writer.writeStartElement("connection");
            writer.writeStartElement("name");
            writer.writeCharacters(connection.getName());
            writer.writeEndElement();
            writer.writeStartElement("url");
            writer.writeCharacters(connection.getUrl());
            writer.writeEndElement();
            writer.writeStartElement("user");
            writer.writeCharacters(connection.getUser());
            writer.writeEndElement();
            writer.writeEndElement();
        }
        writer.writeEndElement();
        writer.writeEndDocument();
        writer.close();
    }

    private void loadConnections() throws XMLStreamException, FileNotFoundException {
        connections.addAll(new Connections().readConnections());
        JPQLEditorTopComponent topComponent = (JPQLEditorTopComponent) WindowManager.getDefault().findTopComponent("JQPLEditorTopComponent");
        topComponent.setConnections(getConnections());
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        listViewPanel = new javax.swing.JPanel();

        listViewPanel.setLayout(new java.awt.BorderLayout());

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(listViewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 387, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(listViewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 346, Short.MAX_VALUE)
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel listViewPanel;
    // End of variables declaration//GEN-END:variables
    @Override
    public void componentOpened() {
        try {
            loadConnections();
            connectionChildFactory = new ConnectionChildFactory(connections);
            explorerManager.setRootContext(new ConnectionNode(connectionChildFactory));
        } catch (XMLStreamException | FileNotFoundException ex) {
            Exceptions.printStackTrace(ex);
        }
    }

    private ConnectionChildFactory connectionChildFactory;

    @Override
    public void componentClosed() {
        // TODO add custom code on component closing
    }

    void writeProperties(java.util.Properties p) {
        // better to version settings since initial version as advocated at
        // http://wiki.apidesign.org/wiki/PropertyFiles
        p.setProperty("version", "1.0");
        // TODO store your settings
    }

    void readProperties(java.util.Properties p) {
        String version = p.getProperty("version");
        // TODO read your settings according to their version
    }

    private final ExplorerManager explorerManager = new ExplorerManager();

    @Override
    public ExplorerManager getExplorerManager() {
        return explorerManager;
    }

    public boolean existsConnection(String name) {
        ListIterator<Connection> listIterator = connections.listIterator();
        while (listIterator.hasNext()) {
            Connection connection = listIterator.next();
            if (connection.getName().equals(name)) {
                return true;
            }
        }
        return false;
    }

    public Set<String> getConnectionNames() {
        return connections.stream().map((connection) -> connection.getName()).collect(Collectors.toSet());
    }

    public void removeConnection(String name) {
        boolean removed = false;
        ListIterator<Connection> listIterator = connections.listIterator();
        while (listIterator.hasNext()) {
            Connection connection = listIterator.next();
            if (connection.getName().equals(name)) {
                listIterator.remove();
                removed = true;
                break;
            }
        }
        if (removed) {
            JPQLEditorTopComponent topComponent = (JPQLEditorTopComponent) WindowManager.getDefault().findTopComponent("JQPLEditorTopComponent");
            topComponent.setConnections(getConnections());
            connectionChildFactory.refreshChildren();
            try {
                saveConnections();
            } catch (IOException | XMLStreamException ex) {
                Exceptions.printStackTrace(ex);
            }
        }
    }

    public void addConnection(Connection connection) {
        connections.add(connection);
        JPQLEditorTopComponent topComponent = (JPQLEditorTopComponent) WindowManager.getDefault().findTopComponent("JQPLEditorTopComponent");
        topComponent.setConnections(getConnections());
        connectionChildFactory.refreshChildren();
        try {
            saveConnections();
        } catch (IOException | XMLStreamException ex) {
            Exceptions.printStackTrace(ex);
        }
    }

    public void updateConnection(Connection connection, Connection updatedConnection) {
        JPQLEditorTopComponent topComponent = (JPQLEditorTopComponent) WindowManager.getDefault().findTopComponent("JQPLEditorTopComponent");
        topComponent.setConnections(getConnections());
        connection.setUrl(updatedConnection.getUrl());
        connection.setUser(updatedConnection.getUser());
        connection.setName(updatedConnection.getName());
        connectionChildFactory.refreshChildren();
        try {
            saveConnections();
        } catch (IOException | XMLStreamException ex) {
            Exceptions.printStackTrace(ex);
        }
    }

}
